<?php
//封装MySQL单例
class MySQLDB {
    private $host;		//主机地址
    private $port;		//端口号
    private $user;		//用户名
    private $pwd;		//密码
    private $dbname;	//数据接名
    private $charset;	//字符集
    private $link;		//连接对象
    private static $instance;
    private function __construct($param) {
        $this->initParam($param);
        $this->initConnect();
    }
    private function __clone() {

    }
    //获取单例
    public static function getInstance($param=array()) {
        if(!self::$instance instanceof self)
            self::$instance=new self($param);
        return self::$instance;
    }
    //初始化参数
    private function initParam($param) {
        $this->host=$param['host']??'127.0.0.1';
        $this->port=$param['port']??'3306';
        $this->user=$param['user']??'';
        $this->pwd=$param['pwd']??'';
        $this->dbname=$param['dbname']??'';
        $this->charset=$param['charset']??'utf8';
    }
    //连接数据库
    private function initConnect() {
        $this->link=@mysqli_connect($this->host,$this->user,$this->pwd,$this->dbname);
        if(mysqli_connect_error()){
            echo '数据库连接失败<br>';
            echo '错误信息：'.mysqli_connect_error(),'<br>';
            echo '错误码：'.mysqli_connect_errno(),'<br>';
            exit;
        }
        mysqli_set_charset($this->link,$this->charset);
    }
    //执行数据库的增、删、改、查
    private function execute($sql) {
        if(!$rs=mysqli_query($this->link,$sql)){
            echo 'SQL语句执行失败<br>';
            echo '错误信息：'.mysqli_error($this->link),'<br>';
            echo '错误码：'.mysqli_errno($this->link),'<br>';
            echo '错误的SQL语句：'.$sql,'<br>';
            exit;
        }
        return $rs;
    }
    /**
     *执行增、删、改
     *@return bool 成功返回true,失败返回false
     */
    public function exec($sql) {
        $key=substr($sql,0,6);
        if(in_array($key,array('insert','update','delete')))
            return $this->execute($sql);
        else{
            echo '非法访问<br>';
            exit;
        }

    }
    //获取自动增长的编号
    public function getLastInsertId() {
        return mysqli_insert_id($this->link);
    }

    //执行查询语句
    private function query($sql) {
        if(substr($sql,0,6)=='select' || substr($sql,0,4)=='show' || substr($sql,0,4)=='desc'){
            return $this->execute($sql);
        }else{
            echo '非法访问<br>';
            exit;
        }
    }
    /**
     *执行查询语句，返回二维数组
     *@$sql string 查询sql语句
     *@type string assoc|num|both
     */
    public function fetchAll($sql,$type='assoc') {
        $rs=$this->query($sql);
        $type=$this->getType($type);
        return mysqli_fetch_all($rs,$type);
    }
    //匹配一维数组
    public function fetchRow($sql,$type='assoc') {
        $list=$this->fetchAll($sql,$type);
        if(!empty($list))
            return $list[0];
        return array();
    }
    //匹配一行一列
    public function fetchColumn($sql) {
        $list=$this->fetchRow($sql,'num');
        if(!empty($list))
            return $list[0];
        return null;
    }

    //获取匹配类型
    private function getType($type) {
        switch($type){
            case 'num':
                return  MYSQLI_NUM;
            case 'both':
                return  MYSQLI_BOTH;
            default:
                return  MYSQLI_ASSOC;
        }
    }
}

//测试
//配置参数
$param=array(
    'user'		=>	'root',
    'pwd'		=>	'root',
    'dbname'	=>	'data'
);
//获取单例
$db=MySQLDB::getInstance($param);
//更新
//$db->exec("update products set proname='青草' where proID=2");
//插入
/*
if($db->exec("insert into news values (null,'aa','bb',unix_timestamp())"))
	echo '编号是：'.$db->getLastInsertId();
*/

//查询
//$list=$db->fetchAll('select * from products','aa');
//$list=$db->fetchRow('select * from products where id=1','aa');

$list=$db->fetchColumn('select count(*) from products');

echo '<pre>';
var_dump($list);


//小结：
//
//1、instanceof 用来判断对象是否属于某个类
//
//2、参数必须从外部传递到内部，不能写死到类的内部。
//
//3、为了保证代码的可重用性，一个方法只实现一个功能，所以初始化参数和连接数据库分到两个方法中。

